<html>

<head>
<title>Noise Sphere</title>
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">

<script type="text/javascript" src="sylvester.js"></script>
<script type="text/javascript" src="glUtils.js"></script>

<script type="text/javascript" src="webgl-utils.js"></script>

<script type="text/javascript" src="music.js"></script>

<script src="SimplexNoise.js" type="text/javascript"></script>
<script src="audiolib.min.js" type="text/javascript"></script>
<script src="NoiseConverter.js" type="text/javascript"></script>
<script src="colorConverter.js" type="text/javascript"></script>
<script type="text/javascript" src="glMatrix-0.9.5.min.js"></script>
<!-- function generators -->
<script type="text/javascript" src="functionGenerators.js"></script>
<!-- noise generators -->
<script type="text/javascript" src="noiseGenerators.js"></script>
<!-- music object -->
<script src="sourceData.js" type="text/javascript"></script>
<script src="Audio.js" type="text/javascript"></script>

<script type="text/javascript">
		// Update output
		function output(value, noise, freq, dur) {			
			document.getElementById("theValue").textContent = value;
			document.getElementById("theNoise").textContent = noise;
			document.getElementById("theFreq").textContent = freq;
			document.getElementById("theDur").textContent = dur;
		}
		
		var sourceData = new sourceDataObject();
		var music = new musicObject(120, 4, sourceData);
</script>
<script id="shader-fs" type="x-shader/x-fragment">
  precision highp float;

uniform sampler2D permTexture;
uniform sampler2D gradTexture;
uniform float time; // Used for texture animation


/*
 * Both 2D and 3D texture coordinates are defined, for testing purposes.
 */
varying vec3 vTextureCoord;


uniform float blue;
uniform float red;
uniform float green;
vec4 color;

/*
 * To create offsets of one texel and one half texel in the
 * texture lookup, we need to know the texture image size.
 */
#define ONE 0.00390625
#define ONEHALF 0.001953125
// The numbers above are 1/256 and 0.5/256, change accordingly
// if you change the code to use another perm/grad texture size.


/*
 * The 5th degree smooth interpolation function for Perlin "improved noise".
 */
float fade(const in float t) {
  return t*t*t*(t*(t*6.0-15.0)+10.0); // Improved fade, yields C2-continuous noise
}

/*
 * Efficient simplex indexing functions by Bill Licea-Kane, ATI. Thanks!
 * (This was originally implemented as a texture lookup. Nice to avoid that.)
 */
void simplex( const in vec3 P, out vec3 offset1, out vec3 offset2 )
{
  vec3 offset0;
 
  vec2 isX = step( P.yz, P.xx );         // P.x >= P.y ? 1.0 : 0.0;  P.x >= P.z ? 1.0 : 0.0;
  offset0.x  = dot( isX, vec2( 1.0 ) );  // Accumulate all P.x >= other channels in offset.x
  offset0.yz = 1.0 - isX;                // Accumulate all P.x <  other channels in offset.yz

  float isY = step( P.z, P.y );          // P.y >= P.z ? 1.0 : 0.0;
  offset0.y += isY;                      // Accumulate P.y >= P.z in offset.y
  offset0.z += 1.0 - isY;                // Accumulate P.y <  P.z in offset.z
 
  // offset0 now contains the unique values 0,1,2 in each channel
  // 2 for the channel greater than other channels
  // 1 for the channel that is less than one but greater than another
  // 0 for the channel less than other channels
  // Equality ties are broken in favor of first x, then y
  // (z always loses ties)

  offset2 = clamp(   offset0, 0.0, 1.0 );
  // offset2 contains 1 in each channel that was 1 or 2
  offset1 = clamp( --offset0, 0.0, 1.0 );
  // offset1 contains 1 in the single channel that was 1
}

void simplex( const in vec4 P, out vec4 offset1, out vec4 offset2, out vec4 offset3 )
{
  vec4 offset0;
 
  vec3 isX = step( P.yzw, P.xxx );        // See comments in 3D simplex function
  offset0.x = dot( isX, vec3( 1.0 ) );
  offset0.yzw = 1.0 - isX;

  vec2 isY = step( P.zw, P.yy );
  offset0.y += dot( isY, vec2( 1.0 ) );
  offset0.zw += 1.0 - isY;
 
  float isZ = step( P.w, P.z );
  offset0.z += isZ;
  offset0.w += 1.0 - isZ;

  // offset0 now contains the unique values 0,1,2,3 in each channel

  offset3 = clamp(   offset0, 0.0, 1.0 );
  offset2 = clamp( --offset0, 0.0, 1.0 );
  offset1 = clamp( --offset0, 0.0, 1.0 );
}


/*
 * 2D classic Perlin noise. Fast, but less useful than 3D noise.
 */
float noise(const in vec2 P)
{
  vec2 Pi = ONE*floor(P)+ONEHALF; // Integer part, scaled and offset for texture lookup
  vec2 Pf = fract(P);             // Fractional part for interpolation

  // Noise contribution from lower left corner
  vec2 grad00 = texture2D(permTexture, Pi).rg * 4.0 - 1.0;
  float n00 = dot(grad00, Pf);

  // Noise contribution from lower right corner
  vec2 grad10 = texture2D(permTexture, Pi + vec2(ONE, 0.0)).rg * 4.0 - 1.0;
  float n10 = dot(grad10, Pf - vec2(1.0, 0.0));

  // Noise contribution from upper left corner
  vec2 grad01 = texture2D(permTexture, Pi + vec2(0.0, ONE)).rg * 4.0 - 1.0;
  float n01 = dot(grad01, Pf - vec2(0.0, 1.0));

  // Noise contribution from upper right corner
  vec2 grad11 = texture2D(permTexture, Pi + vec2(ONE, ONE)).rg * 4.0 - 1.0;
  float n11 = dot(grad11, Pf - vec2(1.0, 1.0));

  // Blend contributions along x
  vec2 n_x = mix(vec2(n00, n01), vec2(n10, n11), fade(Pf.x));

  // Blend contributions along y
  float n_xy = mix(n_x.x, n_x.y, fade(Pf.y));

  // We're done, return the final noise value.
  return n_xy;
}


/*
 * 3D classic noise. Slower, but a lot more useful than 2D noise.
 */
float noise(const in vec3 P)
{
  vec3 Pi = ONE*floor(P)+ONEHALF; // Integer part, scaled so +1 moves one texel
                                  // and offset 1/2 texel to sample texel centers
  vec3 Pf = fract(P);     // Fractional part for interpolation

  // Noise contributions from (x=0, y=0), z=0 and z=1
  float perm00 = texture2D(permTexture, Pi.xy).a ;
  vec3  grad000 = texture2D(permTexture, vec2(perm00, Pi.z)).rgb * 4.0 - 1.0;
  float n000 = dot(grad000, Pf);
  vec3  grad001 = texture2D(permTexture, vec2(perm00, Pi.z + ONE)).rgb * 4.0 - 1.0;
  float n001 = dot(grad001, Pf - vec3(0.0, 0.0, 1.0));

  // Noise contributions from (x=0, y=1), z=0 and z=1
  float perm01 = texture2D(permTexture, Pi.xy + vec2(0.0, ONE)).a ;
  vec3  grad010 = texture2D(permTexture, vec2(perm01, Pi.z)).rgb * 4.0 - 1.0;
  float n010 = dot(grad010, Pf - vec3(0.0, 1.0, 0.0));
  vec3  grad011 = texture2D(permTexture, vec2(perm01, Pi.z + ONE)).rgb * 4.0 - 1.0;
  float n011 = dot(grad011, Pf - vec3(0.0, 1.0, 1.0));

  // Noise contributions from (x=1, y=0), z=0 and z=1
  float perm10 = texture2D(permTexture, Pi.xy + vec2(ONE, 0.0)).a ;
  vec3  grad100 = texture2D(permTexture, vec2(perm10, Pi.z)).rgb * 4.0 - 1.0;
  float n100 = dot(grad100, Pf - vec3(1.0, 0.0, 0.0));
  vec3  grad101 = texture2D(permTexture, vec2(perm10, Pi.z + ONE)).rgb * 4.0 - 1.0;
  float n101 = dot(grad101, Pf - vec3(1.0, 0.0, 1.0));

  // Noise contributions from (x=1, y=1), z=0 and z=1
  float perm11 = texture2D(permTexture, Pi.xy + vec2(ONE, ONE)).a ;
  vec3  grad110 = texture2D(permTexture, vec2(perm11, Pi.z)).rgb * 4.0 - 1.0;
  float n110 = dot(grad110, Pf - vec3(1.0, 1.0, 0.0));
  vec3  grad111 = texture2D(permTexture, vec2(perm11, Pi.z + ONE)).rgb * 4.0 - 1.0;
  float n111 = dot(grad111, Pf - vec3(1.0, 1.0, 1.0));

  // Blend contributions along x
  vec4 n_x = mix(vec4(n000, n001, n010, n011),
                 vec4(n100, n101, n110, n111), fade(Pf.x));

  // Blend contributions along y
  vec2 n_xy = mix(n_x.xy, n_x.zw, fade(Pf.y));

  // Blend contributions along z
  float n_xyz = mix(n_xy.x, n_xy.y, fade(Pf.z));

  // We're done, return the final noise value.
  return n_xyz;
}


/*
 * 4D classic noise. Slow, but very useful. 4D simplex noise is a lot faster.
 *
 * This function performs 8 texture lookups and 16 dependent texture lookups,
 * 16 dot products, 4 mix operations and a lot of additions and multiplications.
 * Needless to say, it's not super fast. But it's not dead slow either.
 */
float noise(const in vec4 P)
{
  vec4 Pi = ONE*floor(P)+ONEHALF; // Integer part, scaled so +1 moves one texel
                                  // and offset 1/2 texel to sample texel centers
  vec4 Pf = fract(P);      // Fractional part for interpolation

  // "n0000" is the noise contribution from (x=0, y=0, z=0, w=0), and so on
  float perm00xy = texture2D(permTexture, Pi.xy).a ;
  float perm00zw = texture2D(permTexture, Pi.zw).a ;
  vec4 grad0000 = texture2D(gradTexture, vec2(perm00xy, perm00zw)).rgba * 4.0 -1.0;
  float n0000 = dot(grad0000, Pf);

  float perm01zw = texture2D(permTexture, Pi.zw  + vec2(0.0, ONE)).a ;
  vec4  grad0001 = texture2D(gradTexture, vec2(perm00xy, perm01zw)).rgba * 4.0 - 1.0;
  float n0001 = dot(grad0001, Pf - vec4(0.0, 0.0, 0.0, 1.0));

  float perm10zw = texture2D(permTexture, Pi.zw  + vec2(ONE, 0.0)).a ;
  vec4  grad0010 = texture2D(gradTexture, vec2(perm00xy, perm10zw)).rgba * 4.0 - 1.0;
  float n0010 = dot(grad0010, Pf - vec4(0.0, 0.0, 1.0, 0.0));

  float perm11zw = texture2D(permTexture, Pi.zw  + vec2(ONE, ONE)).a ;
  vec4  grad0011 = texture2D(gradTexture, vec2(perm00xy, perm11zw)).rgba * 4.0 - 1.0;
  float n0011 = dot(grad0011, Pf - vec4(0.0, 0.0, 1.0, 1.0));

  float perm01xy = texture2D(permTexture, Pi.xy + vec2(0.0, ONE)).a ;
  vec4  grad0100 = texture2D(gradTexture, vec2(perm01xy, perm00zw)).rgba * 4.0 - 1.0;
  float n0100 = dot(grad0100, Pf - vec4(0.0, 1.0, 0.0, 0.0));

  vec4  grad0101 = texture2D(gradTexture, vec2(perm01xy, perm01zw)).rgba * 4.0 - 1.0;
  float n0101 = dot(grad0101, Pf - vec4(0.0, 1.0, 0.0, 1.0));

  vec4  grad0110 = texture2D(gradTexture, vec2(perm01xy, perm10zw)).rgba * 4.0 - 1.0;
  float n0110 = dot(grad0110, Pf - vec4(0.0, 1.0, 1.0, 0.0));

  vec4  grad0111 = texture2D(gradTexture, vec2(perm01xy, perm11zw)).rgba * 4.0 - 1.0;
  float n0111 = dot(grad0111, Pf - vec4(0.0, 1.0, 1.0, 1.0));

  float perm10xy = texture2D(permTexture, Pi.xy + vec2(ONE, 0.0)).a ;
  vec4  grad1000 = texture2D(gradTexture, vec2(perm10xy, perm00zw)).rgba * 4.0 - 1.0;
  float n1000 = dot(grad1000, Pf - vec4(1.0, 0.0, 0.0, 0.0));

  vec4  grad1001 = texture2D(gradTexture, vec2(perm10xy, perm01zw)).rgba * 4.0 - 1.0;
  float n1001 = dot(grad1001, Pf - vec4(1.0, 0.0, 0.0, 1.0));

  vec4  grad1010 = texture2D(gradTexture, vec2(perm10xy, perm10zw)).rgba * 4.0 - 1.0;
  float n1010 = dot(grad1010, Pf - vec4(1.0, 0.0, 1.0, 0.0));

  vec4  grad1011 = texture2D(gradTexture, vec2(perm10xy, perm11zw)).rgba * 4.0 - 1.0;
  float n1011 = dot(grad1011, Pf - vec4(1.0, 0.0, 1.0, 1.0));

  float perm11xy = texture2D(permTexture, Pi.xy + vec2(ONE, ONE)).a ;
  vec4  grad1100 = texture2D(gradTexture, vec2(perm11xy, perm00zw)).rgba * 4.0 - 1.0;
  float n1100 = dot(grad1100, Pf - vec4(1.0, 1.0, 0.0, 0.0));

  vec4  grad1101 = texture2D(gradTexture, vec2(perm11xy, perm01zw)).rgba * 4.0 - 1.0;
  float n1101 = dot(grad1101, Pf - vec4(1.0, 1.0, 0.0, 1.0));

  vec4  grad1110 = texture2D(gradTexture, vec2(perm11xy, perm10zw)).rgba * 4.0 - 1.0;
  float n1110 = dot(grad1110, Pf - vec4(1.0, 1.0, 1.0, 0.0));

  vec4  grad1111 = texture2D(gradTexture, vec2(perm11xy, perm11zw)).rgba * 4.0 - 1.0;
  float n1111 = dot(grad1111, Pf - vec4(1.0, 1.0, 1.0, 1.0));

  // Blend contributions along x
  float fadex = fade(Pf.x);
  vec4 n_x0 = mix(vec4(n0000, n0001, n0010, n0011),
                  vec4(n1000, n1001, n1010, n1011), fadex);
  vec4 n_x1 = mix(vec4(n0100, n0101, n0110, n0111),
                  vec4(n1100, n1101, n1110, n1111), fadex);

  // Blend contributions along y
  vec4 n_xy = mix(n_x0, n_x1, fade(Pf.y));

  // Blend contributions along z
  vec2 n_xyz = mix(n_xy.xy, n_xy.zw, fade(Pf.z));

  // Blend contributions along w
  float n_xyzw = mix(n_xyz.x, n_xyz.y, fade(Pf.w));

  // We're done, return the final noise value.
  return n_xyzw;
}


/*
 * 2D simplex noise. Somewhat slower but much better looking than classic noise.
 */
float snoise(const in vec2 P) {

// Skew and unskew factors are a bit hairy for 2D, so define them as constants
// This is (sqrt(3.0)-1.0)/2.0
#define F2 0.366025403784
// This is (3.0-sqrt(3.0))/6.0
#define G2 0.211324865405

  // Skew the (x,y) space to determine which cell of 2 simplices we're in
 	float s = (P.x + P.y) * F2;   // Hairy factor for 2D skewing
  vec2 Pi = floor(P + s);
  float t = (Pi.x + Pi.y) * G2; // Hairy factor for unskewing
  vec2 P0 = Pi - t; // Unskew the cell origin back to (x,y) space
  Pi = Pi * ONE + ONEHALF; // Integer part, scaled and offset for texture lookup

  vec2 Pf0 = P - P0;  // The x,y distances from the cell origin

  // For the 2D case, the simplex shape is an equilateral triangle.
  // Find out whether we are above or below the x=y diagonal to
  // determine which of the two triangles we're in.
  vec2 o1;
  if(Pf0.x > Pf0.y) o1 = vec2(1.0, 0.0);  // +x, +y traversal order
  else o1 = vec2(0.0, 1.0);               // +y, +x traversal order

  // Noise contribution from simplex origin
  vec2 grad0 = texture2D(permTexture, Pi).rg * 4.0 - 1.0;
  float t0 = 0.5 - dot(Pf0, Pf0);
  float n0;
  if (t0 < 0.0) n0 = 0.0;
  else {
    t0 *= t0;
    n0 = t0 * t0 * dot(grad0, Pf0);
  }

  // Noise contribution from middle corner
  vec2 Pf1 = Pf0 - o1 + G2;
  vec2 grad1 = texture2D(permTexture, Pi + o1*ONE).rg * 4.0 - 1.0;
  float t1 = 0.5 - dot(Pf1, Pf1);
  float n1;
  if (t1 < 0.0) n1 = 0.0;
  else {
    t1 *= t1;
    n1 = t1 * t1 * dot(grad1, Pf1);
  }
  
  // Noise contribution from last corner
  vec2 Pf2 = Pf0 - vec2(1.0-2.0*G2);
  vec2 grad2 = texture2D(permTexture, Pi + vec2(ONE, ONE)).rg * 4.0 - 1.0;
  float t2 = 0.5 - dot(Pf2, Pf2);
  float n2;
  if(t2 < 0.0) n2 = 0.0;
  else {
    t2 *= t2;
    n2 = t2 * t2 * dot(grad2, Pf2);
  }

  // Sum up and scale the result to cover the range [-1,1]
  return 70.0 * (n0 + n1 + n2);
}


/*
 * 3D simplex noise. Comparable in speed to classic noise, better looking.
 */
float snoise(const in vec3 P) {

// The skewing and unskewing factors are much simpler for the 3D case
#define F3 0.333333333333
#define G3 0.166666666667

  // Skew the (x,y,z) space to determine which cell of 6 simplices we're in
 	float s = (P.x + P.y + P.z) * F3; // Factor for 3D skewing
  vec3 Pi = floor(P + s);
  float t = (Pi.x + Pi.y + Pi.z) * G3;
  vec3 P0 = Pi - t; // Unskew the cell origin back to (x,y,z) space
  Pi = Pi * ONE + ONEHALF; // Integer part, scaled and offset for texture lookup

  vec3 Pf0 = P - P0;  // The x,y distances from the cell origin

  // For the 3D case, the simplex shape is a slightly irregular tetrahedron.
  // To find out which of the six possible tetrahedra we're in, we need to
  // determine the magnitude ordering of x, y and z components of Pf0.
  vec3 o1;
  vec3 o2;
  simplex(Pf0, o1, o2);

  // Noise contribution from simplex origin
  float perm0 = texture2D(permTexture, Pi.xy).a;
  vec3  grad0 = texture2D(permTexture, vec2(perm0, Pi.z)).rgb * 4.0 - 1.0;
  float t0 = 0.6 - dot(Pf0, Pf0);
  float n0;
  if (t0 < 0.0) n0 = 0.0;
  else {
    t0 *= t0;
    n0 = t0 * t0 * dot(grad0, Pf0);
  }

  // Noise contribution from second corner
  vec3 Pf1 = Pf0 - o1 + G3;
  float perm1 = texture2D(permTexture, Pi.xy + o1.xy*ONE).a;
  vec3  grad1 = texture2D(permTexture, vec2(perm1, Pi.z + o1.z*ONE)).rgb * 4.0 - 1.0;
  float t1 = 0.6 - dot(Pf1, Pf1);
  float n1;
  if (t1 < 0.0) n1 = 0.0;
  else {
    t1 *= t1;
    n1 = t1 * t1 * dot(grad1, Pf1);
  }
  
  // Noise contribution from third corner
  vec3 Pf2 = Pf0 - o2 + 2.0 * G3;
  float perm2 = texture2D(permTexture, Pi.xy + o2.xy*ONE).a;
  vec3  grad2 = texture2D(permTexture, vec2(perm2, Pi.z + o2.z*ONE)).rgb * 4.0 - 1.0;
  float t2 = 0.6 - dot(Pf2, Pf2);
  float n2;
  if (t2 < 0.0) n2 = 0.0;
  else {
    t2 *= t2;
    n2 = t2 * t2 * dot(grad2, Pf2);
  }
  
  // Noise contribution from last corner
  vec3 Pf3 = Pf0 - vec3(1.0-3.0*G3);
  float perm3 = texture2D(permTexture, Pi.xy + vec2(ONE, ONE)).a;
  vec3  grad3 = texture2D(permTexture, vec2(perm3, Pi.z + ONE)).rgb * 4.0 - 1.0;
  float t3 = 0.6 - dot(Pf3, Pf3);
  float n3;
  if(t3 < 0.0) n3 = 0.0;
  else {
    t3 *= t3;
    n3 = t3 * t3 * dot(grad3, Pf3);
  }

  // Sum up and scale the result to cover the range [-1,1]
  return 32.0 * (n0 + n1 + n2 + n3);
}


/*
 * 4D simplex noise. A lot faster than classic 4D noise, and better looking.
 */

  void main(void) {
	//red = Math.random();
    //blue = ridgedmfDefault(vec4(vTextureCoord.xyz, time / 5.0), 2);
	//red = time/1000;
	//green = 0.1;
    color = vec4(red, green, blue, 1.0);
    gl_FragColor = color;
  }
</script>

<script id="shader-vs" type="x-shader/x-vertex">
  attribute vec3 aVertexPosition;
  attribute vec3 aTextureCoord;

  uniform mat4 uMVMatrix;
  uniform mat4 uPMatrix;

  varying vec3 vTextureCoord;


  void main(void) {
    gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
    vTextureCoord = aTextureCoord;
  }
</script>


<script type="text/javascript">

var perm;
var grad3;
var grad4;
function initData() {
    perm = new Uint8Array([151,160,137,91,90,15,
                                     131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
                                     190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
                                     88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
                                     77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
                                     102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
                                     135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
                                     5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
                                     223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
                                     129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
                                     251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
                                     49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
                                     138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180,
                                     151,160,137,91,90,15,
                                     131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
                                     190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
                                     88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
                                     77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
                                     102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
                                     135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
                                     5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
                                     223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
                                     129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
                                     251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
                                     49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
                                     138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180
                                    ]);
    grad3 = new Int8Array([0,1,1,0,1,-1,0,-1,1,0,-1,-1,
                   1,0,1,1,0,-1,-1,0,1,-1,0,-1,
                   1,1,0,1,-1,0,-1,1,0,-1,-1,0,
                   1,0,-1,-1,0,-1,0,-1,1,0,1,1]);
    grad4 = new Int8Array([0,1,1,1, 0,1,1,-1, 0,1,-1,1, 0,1,-1,-1,
                   0,-1,1,1, 0,-1,1,-1, 0,-1,-1,1, 0,-1,-1,-1,
                   1,0,1,1, 1,0,1,-1, 1,0,-1,1, 1,0,-1,-1,
                   -1,0,1,1, -1,0,1,-1, -1,0,-1,1, -1,0,-1,-1,
                   1,1,0,1, 1,1,0,-1, 1,-1,0,1, 1,-1,0,-1,
                   -1,1,0,1, -1,1,0,-1, -1,-1,0,1, -1,-1,0,-1,
                   1,1,1,0, 1,1,-1,0, 1,-1,1,0, 1,-1,-1,0,
                   -1,1,1,0, -1,1,-1,0, -1,-1,1,0, -1,-1,-1,0]);
}
  var gl;
  function initGL(canvas) {
    try {
      gl = WebGLUtils.setupWebGL(canvas);
      gl.viewportWidth = canvas.width;
      gl.viewportHeight = canvas.height;
    } catch(e) { }
    if (!gl) {
      //document.writeln("");
    }
  }


  function getShader(gl, id) {
    var shaderScript = document.getElementById(id);
    if (!shaderScript) {
      return null;
    }

    var str = "";
    var k = shaderScript.firstChild;
    while (k) {
      if (k.nodeType == 3) {
        str += k.textContent;
      }
      k = k.nextSibling;
    }

    var shader;
    if (shaderScript.type == "x-shader/x-fragment") {
      shader = gl.createShader(gl.FRAGMENT_SHADER);
    } else if (shaderScript.type == "x-shader/x-vertex") {
      shader = gl.createShader(gl.VERTEX_SHADER);
    } else {
      return null;
    }

    gl.shaderSource(shader, str);
    gl.compileShader(shader);

    if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
      canvas3d.style.display = "none";
      crap_gpu.style.display = "block";
      //alert(gl.getShaderInfoLog(shader));
      return null;
    }

    return shader;
  }


  var shaderProgram;
  function initShaders() {
    var fragmentShader = getShader(gl, "shader-fs");
    var vertexShader = getShader(gl, "shader-vs");

    shaderProgram = gl.createProgram();
    gl.attachShader(shaderProgram, vertexShader);
    gl.attachShader(shaderProgram, fragmentShader);
    gl.linkProgram(shaderProgram);

    if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
      canvas3d.style.display = "none";
      crap_gpu.style.display = "block";
      //alert("Could not initialise shaders");
    }

    gl.useProgram(shaderProgram);

    shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");
    gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute);

    shaderProgram.textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord");
    gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute);

    shaderProgram.pMatrixUniform = gl.getUniformLocation(shaderProgram, "uPMatrix");
    shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix");

    shaderProgram.permSampler = gl.getUniformLocation(shaderProgram, "permTexture");
    shaderProgram.gradSampler = gl.getUniformLocation(shaderProgram, "gradTexture");

    shaderProgram.timeUniform = gl.getUniformLocation(shaderProgram, "time");
	shaderProgram.greenUniform = gl.getUniformLocation(shaderProgram, "green");
	shaderProgram.redUniform = gl.getUniformLocation(shaderProgram, "red");
	shaderProgram.blueUniform = gl.getUniformLocation(shaderProgram, "blue");
  }

  var permTexture;
  function initPermTexture() {
    var width = 256;
    var components = 4;
    var pixels = new Uint8Array(width * width * components);
    for(var i = 0; i < width; i++) {
      for(var j = 0; j < width; j++) {
        var offset = (i * width + j) * components;
        var value = perm[(j + perm[i]) & 0xff];
        pixels[offset] = grad3[(value & 0x0f) * 3 + 0] * 64 + 64;
        pixels[offset + 1] = grad3[(value & 0x0f) * 3 + 1] * 64 + 64;
        pixels[offset + 2] = grad3[(value & 0x0f) * 3 + 2] * 64 + 64;
        pixels[offset + 3] = value;
      }
    }
    gl.pixelStorei ( gl.UNPACK_ALIGNMENT, 1 );
    permTexture = gl.createTexture();
    
    gl.bindTexture(gl.TEXTURE_2D, permTexture);
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA,
      width, width, 0, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
    gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST );
    gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST );
  }

  var gradTexture;
  function initGradTexture()
  {
    var width = 256;
    var components = 4;
    var pixels = new Uint8Array(width * width * components);
    for(var i = 0; i<width; i++) {
      for(var j = 0; j<width; j++) {
        var offset = (i * width + j) * components;
        var value = perm[(j+perm[i]) & 0xff];
        pixels[offset] = grad4[(value & 0x1f) * 4 + 0] * 64 + 64;   // Gradient x
        pixels[offset+1] = grad4[(value & 0x1f) * 4 + 1] * 64 + 64; // Gradient y
        pixels[offset+2] = grad4[(value & 0x1f) * 4 + 2] * 64 + 64; // Gradient z
        pixels[offset+3] = grad4[(value & 0x1f) * 4 + 3] * 64 + 64; // Gradient w
      }
    }
    gl.pixelStorei ( gl.UNPACK_ALIGNMENT, 1 );
    gradTexture = gl.createTexture();

    gl.bindTexture(gl.TEXTURE_2D, gradTexture);
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA,
      width, width, 0, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
    gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST );
    gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST );
  }

  var mvMatrix;
  var mvMatrixStack = [];

  function mvPushMatrix(m) {
    if (m) {
      mvMatrixStack.push(m.dup());
      mvMatrix = m.dup();
    } else {
      mvMatrixStack.push(mvMatrix.dup());
    }
  }

  function mvPopMatrix() {
    if (mvMatrixStack.length == 0) {
      throw "Invalid popMatrix!";
    }
    mvMatrix = mvMatrixStack.pop();
    return mvMatrix;
  }

  function loadIdentity() {
    mvMatrix = Matrix.I(4);
  }


  function multMatrix(m) {
    mvMatrix = mvMatrix.x(m);
  }

  function mvTranslate(v) {
    var m = Matrix.Translation($V([v[0], v[1], v[2]])).ensure4x4();
    multMatrix(m);
  }

  function mvRotate(ang, v) {
    var arad = ang * Math.PI / 180.0;
    var m = Matrix.Rotation(arad, $V([v[0], v[1], v[2]])).ensure4x4();
    multMatrix(m);
  }

  var pMatrix;
  function perspective(fovy, aspect, znear, zfar) {
    pMatrix = makePerspective(fovy, aspect, znear, zfar);
  }


  function setMatrixUniforms() {
    gl.uniformMatrix4fv(shaderProgram.pMatrixUniform, false, new Float32Array(pMatrix.flatten()));
    gl.uniformMatrix4fv(shaderProgram.mvMatrixUniform, false, new Float32Array(mvMatrix.flatten()));
  }

    var sphereVertexPositionBuffer;
    var sphereVertexNormalBuffer;
    var sphereVertexTextureCoordBuffer;
    var sphereVertexIndexBuffer;

    function initBuffers() {
        var latitudeBands = 30;
        var longitudeBands = 30;
        var radius = 1.5;

        var vertexPositionData = [];
        var normalData = [];
        var textureCoordData = [];
        for (var latNumber=0; latNumber <= latitudeBands; latNumber++) {
            var theta = latNumber * Math.PI / latitudeBands;
            var sinTheta = Math.sin(theta);
            var cosTheta = Math.cos(theta);

            for (var longNumber=0; longNumber <= longitudeBands; longNumber++) {
                var phi = longNumber * 2 * Math.PI / longitudeBands;
                var sinPhi = Math.sin(phi);
                var cosPhi = Math.cos(phi);

                var x = cosPhi * sinTheta;
                var y = cosTheta;
                var z = sinPhi * sinTheta;
                var u = 1 - (longNumber / longitudeBands);
                var v = 1 - (latNumber / latitudeBands);

                normalData.push(x);
                normalData.push(y);
                normalData.push(z);
                textureCoordData.push(u);
                textureCoordData.push(v);
                vertexPositionData.push(radius * x);
                vertexPositionData.push(radius * y);
                vertexPositionData.push(radius * z);
            }
        }

        var indexData = [];
        for (var latNumber=0; latNumber < latitudeBands; latNumber++) {
            for (var longNumber=0; longNumber < longitudeBands; longNumber++) {
                var first = (latNumber * (longitudeBands + 1)) + longNumber;
                var second = first + longitudeBands + 1;
                indexData.push(first);
                indexData.push(second);
                indexData.push(first + 1);

                indexData.push(second);
                indexData.push(second + 1);
                indexData.push(first + 1);
            }
        }

        sphereVertexNormalBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, sphereVertexNormalBuffer);
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(normalData), gl.STATIC_DRAW);
        sphereVertexNormalBuffer.itemSize = 3;
        sphereVertexNormalBuffer.numItems = normalData.length / 3;

        sphereVertexTextureCoordBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, sphereVertexTextureCoordBuffer);
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textureCoordData), gl.STATIC_DRAW);
        sphereVertexTextureCoordBuffer.itemSize = 2;
        sphereVertexTextureCoordBuffer.numItems = textureCoordData.length / 2;

        sphereVertexPositionBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, sphereVertexPositionBuffer);
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexPositionData), gl.STATIC_DRAW);
        sphereVertexPositionBuffer.itemSize = 3;
        sphereVertexPositionBuffer.numItems = vertexPositionData.length / 3;

        sphereVertexIndexBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, sphereVertexIndexBuffer);
        gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indexData), gl.STATIC_DRAW);
        sphereVertexIndexBuffer.itemSize = 1;
        sphereVertexIndexBuffer.numItems = indexData.length;
    }

  var xRot = 0;
  var yRot = 0;
  var zRot = 0;
  function drawScene() {
    gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
    gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

    perspective(45, gl.viewportWidth / gl.viewportHeight, 0.1, 100.0);
    loadIdentity();

    mvTranslate([0.0, 0.0, -5.0])

    mvRotate(xRot, [1, 0, 0]);
    mvRotate(yRot, [0, 1, 0]);
    mvRotate(zRot, [0, 0, 1]);

    gl.bindBuffer(gl.ARRAY_BUFFER, sphereVertexPositionBuffer);
    gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, sphereVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);

    gl.bindBuffer(gl.ARRAY_BUFFER, sphereVertexTextureCoordBuffer);
    gl.vertexAttribPointer(shaderProgram.textureCoordAttribute, sphereVertexTextureCoordBuffer.itemSize, gl.FLOAT, false, 0, 0);

    gl.activeTexture(gl.TEXTURE0);
    gl.bindTexture(gl.TEXTURE_2D, permTexture);
    gl.uniform1i(shaderProgram.permSampler, 0);

    gl.activeTexture(gl.TEXTURE1);
    gl.bindTexture(gl.TEXTURE_2D, gradTexture);
    gl.uniform1i(shaderProgram.gradSampler, 1);

    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, sphereVertexIndexBuffer);
    setMatrixUniforms();
    gl.drawElements(gl.TRIANGLES, sphereVertexIndexBuffer.numItems, gl.UNSIGNED_SHORT, 0);
  }


  var lastTime = 0;
  var x;
  var frequency;
  var reed;
  var greeen;
  var bluue;
  var midi;
  function animate() {
    var dateTime = new Date();
    var timeNow = dateTime.getTime();
    if (lastTime != 0) {
      var elapsed = timeNow - lastTime;
      var seconds = timeNow / 1000.0;
      /*** in/out timer ***/
      var interval = 65536.0;
      var mod_outer = seconds % (interval * 2.0);
      var mod_inner = seconds % interval;
      var in_out = 0;
	  
	  
	  //sourceData.getSourceData();
	  //sourceData.setNoiseGenerator(0);
	  //sourceData.setFunctionGenerator(0);
	  //var y = (sourceData.getValueMax()-x)/(sourceData.getValueMax()-sourceData.getValueMin());
	  if(mod_inner%2>=0&&mod_inner%2<=0.02){
		  //x = sourceData.getValue();
		  //midi = valueToMidi(x,sourceData.getValueMin(),sourceData.getValueMax());
		  //frequency = midiToFrequency(midi);
		  frequency = lead.frequency;
		  document.getElementById("theValue").textContent = x;
		  document.getElementById("theFreq").textContent = frequency;
		  document.getElementById("theNoise").textContent = midi;
		  //var reed = frequencyToRed(250);
		  //var greeen = frequencyToGreen(250);
		  reed = frequencyToRed(frequency);
		  greeen = frequencyToGreen(frequency);
		  bluue = frequencyToBlue(frequency);
		  //sourceData = sourceData.getSourceData();
	  }
      if(mod_outer > interval) { in_out = interval - mod_inner; }
      else { in_out = mod_outer; }
      /*** end in/out timer ***/
      gl.uniform1f(shaderProgram.timeUniform, in_out);
	  gl.uniform1f(shaderProgram.redUniform, reed);
	  gl.uniform1f(shaderProgram.greenUniform, greeen);
	  gl.uniform1f(shaderProgram.blueUniform, bluue);
      var elapsed_scaled = elapsed / 10.0;
      xRot += (90 * elapsed_scaled) / 1000.0;
      yRot += (90 * elapsed_scaled) / 1000.0;
      zRot += (90 * elapsed_scaled) / 1000.0;
    }
    lastTime = timeNow;
  }

  var canvas;
  function webGLStart() {
      crap_gpu.style.display = "none";
      canvas = document.getElementById("canvas3d");
	  //startSystem();
      initGL(canvas);

      if(gl) {
        canvas3d_img.style.display = "none";
        warn_no_gl.style.display="none";
        initData();
        initShaders();
        initBuffers();

        initPermTexture();
        initGradTexture();

        gl.clearColor(0.0, 0.0, 0.0, 1.0);
        gl.clearDepth(1.0);

        gl.enable(gl.DEPTH_TEST);
        gl.depthFunc(gl.LEQUAL);

        render();
      }
  }

  function render() {
    window.requestAnimFrame(render, canvas);
    drawScene();
    animate();
  }
  
  
  
  
  
  
var   leadNoteLength = 0,
		fade = 0,
		fadePoint = 0,
		dev, sampleRate, lead;
		
var sourceData = new sourceDataObject();
var music = new musicObject(120, 4, sourceData);

// called from audioCallback
// inputs
// gets the next song note
// gets the song notes per beat and tempo
// outputs
// sets outgoing lead note freq and length from song note and song
// sets fadepoint for this lead note
// for a chord, we create an array of lead notes (not implemented).
function loadNote () {
		var note = music.getNextNote();

		// Reset oscillator
		lead.frequency = 0;
		lead.reset();

		// Set oscillator frequency
		lead.frequency = note.freq;
				
		// Calculate note length in samples
		leadNoteLength = Math.floor(note.dur * sampleRate * 60 * 
				music.getNotesPerBeat() / music.getTempo()
				);

		// reset fade
		fade = 0;

		// define fade point
		fadePoint = leadNoteLength - 300;
		
		
		  frequency = lead.frequency;
		  document.getElementById("theValue").textContent = x;
		  document.getElementById("theFreq").textContent = frequency;
		  document.getElementById("theNoise").textContent = midi;
		  //var reed = frequencyToRed(250);
		  //var greeen = frequencyToGreen(250);
		  reed = frequencyToRed(frequency);
		  greeen = frequencyToGreen(frequency);
		  bluue = frequencyToBlue(frequency);
		  gl.uniform1f(shaderProgram.timeUniform, in_out);
		  gl.uniform1f(shaderProgram.redUniform, reed);
		  gl.uniform1f(shaderProgram.greenUniform, greeen);
	      gl.uniform1f(shaderProgram.blueUniform, bluue);
}

// audioLib calls this when the audio buffer needs filling
// plays a lead note
function audioCallback (buffer, channelCount){
		var l = buffer.length,
				sample, note, n, current;

		// loop through each sample in the buffer
		for (current=0; current<l; current+= channelCount){

				if (leadNoteLength == 0) loadNote();

				// fade in
				if (leadNoteLength > fadePoint){
						fade = 1 - (leadNoteLength-fadePoint)/300;
				// fade out
				} else if (leadNoteLength<300){
						fade = leadNoteLength/300;
				} else {
						fade = 1;
				}

				sample = 0;

				// Generate oscillator
				lead.generate();

				// Get oscillator mix and multiply by .5 to reduce amplitude
				// for a chord, we add the samples together.
				sample = lead.getMix()*0.5*fade;

				// Fill buffer for each channel
				for (n=0; n<channelCount; n++){
						buffer[current + n] = sample;
				} // for
				//render();
				leadNoteLength -= 1;
		} // for 
}

// start the system
var started = 0;
function startSystem() {
		if (started == 0) {
				started = 1;
				// Create an instance of the AudioDevice class
				dev = audioLib.AudioDevice(audioCallback /* callback for the buffer fills */, 2 /* channelCount */);

				sampleRate = dev.sampleRate;

				// Create an instance of the Oscillator class... not sure what the 440 is all about - the first note?
				lead = audioLib.Oscillator(sampleRate, 440);
		} // if
}


</script>

</head>


<body onload="webGLStart();" bgcolor="black" style="color:blue;">

  <center>
    <img id="canvas3d_img" src="Noisesphere.jpg"/><br>
    <canvas id="canvas3d" width="640" height="480"></canvas><br>
    <a href="http://twitter.com/share?text=CheckItOut%20WebGL%20Demo&url=http://www.pcprogramming.com">Share This on Twitter</a>
  </center>
  <p id="warn_no_gl">This site requires Chrome 9 or Firefox 4.0, please download 
    one of these browsers and revisit this site for a full WebGL experience.  Get FireFox 
    <a href="http://www.mozilla.com/en-US/firefox/beta">here</a></p>
  <p id="crap_gpu">Your PC needs a bigger graphics card, this site requires shader model 3.0 or higher.</p>

  <p>Check back often, we'll be adding more demos soon.</p>
<div style="margin-bottom:20px">
    <span>Press the button to start the system.</span><br/>
    <input type="button" value="Start" id="startButton" onclick="javascript:startSystem();" />
  </div>
  <div style="margin-bottom:20px">
        <div><span>Press F5 to stop the system.</span></div>
  </div>
  
  <div style="margin-bottom:20px">
  	<div style="float:left;margin-right:20px;">
		<div><span style="display:none;color:#990000;" id="glMsg"></span></div>
		<canvas id="theCanvas" style="border: none;" width="500" height="500"></canvas>
	</div>
	<div style="float:left; margin-right:20px;">
		<h4 style="margin-bottom:2px;">Select input:</h4>
		<input name="functionSelect" checked="true" type="radio" value="0" onclick="javascript:sourceData.setFunctionGenerator(0);" />
		<span>Sine Wave</span><br/>
		<input name="functionSelect" type="radio" value="1" onclick="javascript:sourceData.setFunctionGenerator(1);" />
		<span>L System</span><br />
		<input name="functionSelect" type="radio" value="2" onclick="javascript:sourceData.setFunctionGenerator(2);" />
		<span>Mary</span>
	</div>
	<div style="float:left; margin-right:20px;">
		<h4 style="margin-bottom:2px;">Select noise:</h4>
		<input name="noiseSelect" checked="true" type="radio" value="0" onclick="javascript:sourceData.setNoiseGenerator(0);" />
		<span>No Noise</span><br/>
		<input name="noiseSelect"type="radio" value="3" onclick="javascript:sourceData.setNoiseGenerator(3);" />
		<span>Random Noise</span><br/>		
		<input  name="noiseSelect" type="radio" value="1" onclick="javascript:sourceData.setNoiseGenerator(1);" />
		<span>White Noise</span><br/>		
		<input name="noiseSelect"type="radio" value="4" onclick="javascript:sourceData.setNoiseGenerator(4);" />
		<span>Pink Noise</span><br/>
		<input name="noiseSelect"type="radio" value="5" onclick="javascript:sourceData.setNoiseGenerator(5);" />
		<span>Brown Noise</span><br/>
		<input name="noiseSelect"type="radio" value="2" onclick="javascript:sourceData.setNoiseGenerator(2);" />
		<span>Perlin Noise</span><br/>		
	</div>	
	<div style="float:left;">
		<h4 style="margin-bottom:2px;">Output:</h4>
		<ul style="margin-top:0">
			<li>Function Value: <span id="theValue">none</span></li>
			<li>Noised Value: <span id="theNoise">none</span></li>
			<li>Frequency: <span id="theFreq">none</span></li>
			<li>Duration: <span id="theDur">none</span></li>
		</ul>
	</div>
	<div style="clear:both;">
  </div>
  
  <div style="margin-bottom:20px">
    <h4>Extended Debug Output:</h4>
        <ul style="margin-top:0">
                <li>Debug Line 1: <span id="debugEcho1">none</span></li>
                <li>Debug Line 2: <span id="debugEcho2">none</span></li>
                <li>Debug Line 3: <span id="debugEcho3">none</span></li>
                <li>Debug Line 4: <span id="debugEcho4">none</span></li>
                <li>Debug Line 5: <span id="debugEcho5">none</span></li>
                <li>Debug Line 6: <span id="debugEcho6">none</span></li>
                <li>Debug Line 7: <span id="debugEcho7">none</span></li>
                <li>Debug Line 8: <span id="debugEcho8">none</span></li>
        </ul>
  </div>
  
  </body>

</html>

